package com.codesynapse.service.impl;

import com.codesynapse.config.AIModelConfig;
import com.codesynapse.dto.AIRequest;
import com.codesynapse.service.AIModelService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(name = "ai.model.ollama.enabled", havingValue = "true")
public class OllamaAIService implements AIModelService {

    private final AIModelConfig aiModelConfig;
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String generateCompletion(String prompt) {
        log.info("发送代码补全请求到Ollama，提示：{}", prompt);
        return sendRequest("/api/generate", createPromptPayload(prompt, 
            "请补全以下Java代码：\n"));
    }

    @Override
    public String generateSQL(String naturalLanguage) {
        log.info("发送SQL生成请求到Ollama，提示：{}", naturalLanguage);
        return sendRequest("/api/generate", createPromptPayload(naturalLanguage,
            "请根据描述生成SQL：\n"));
    }

    @Override
    public String searchCode(String query) {
        log.info("发送代码搜索请求到Ollama，查询：{}", query);
        return sendRequest("/api/generate", createPromptPayload(query,
            "请搜索相关代码：\n"));
    }

    @Override
    public String generateCompletionWithContext(AIRequest request) {
        log.info("发送上下文代码补全请求到Ollama，提示：{}，上下文：{}", request.getPrompt(), request.getContext());
        String prompt = String.format("上下文代码：\n%s\n\n请补全以下代码：\n%s", 
            request.getContext(), request.getPrompt());
        return sendRequest("/api/generate", createPromptPayload(prompt, ""));
    }

    @Override
    public String generateSQLWithDialect(AIRequest request) {
        log.info("发送SQL生成请求到Ollama，提示：{}，数据库类型：{}", request.getPrompt(), request.getDialect());
        String prompt = String.format("使用%s数据库语法，%s", 
            request.getDialect(), request.getPrompt());
        return sendRequest("/api/generate", createPromptPayload(prompt, ""));
    }

    @Override
    public String searchCodeWithFilters(AIRequest request) {
        log.info("发送代码搜索请求到Ollama，查询：{}，语言：{}，框架：{}", 
            request.getPrompt(), request.getLanguage(), request.getFramework());
        String prompt = String.format("在%s语言的%s框架中，%s", 
            request.getLanguage(), request.getFramework(), request.getPrompt());
        return sendRequest("/api/generate", createPromptPayload(prompt, ""));
    }

    @Override
    public String analyzeCode(String code) {
        log.info("发送代码分析请求到Ollama");
        return sendRequest("/api/generate", createPromptPayload(code,
            "请分析以下代码，指出可能的问题和改进建议：\n"));
    }

    @Override
    public String optimizeCode(String code) {
        log.info("发送代码优化请求到Ollama");
        return sendRequest("/api/generate", createPromptPayload(code,
            "请优化以下代码，提供更高效的实现：\n"));
    }

    @Override
    public String generateTestCases(String code) {
        log.info("发送测试用例生成请求到Ollama");
        return sendRequest("/api/generate", createPromptPayload(code,
            "请为以下代码生成单元测试用例：\n"));
    }

    @Override
    public String explainCode(String code) {
        log.info("发送代码解释请求到Ollama");
        return sendRequest("/api/generate", createPromptPayload(code,
            "请详细解释以下代码的功能和实现原理：\n"));
    }

    private String sendRequest(String endpoint, Map<String, Object> payload) {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            String url = aiModelConfig.getOllama().getBaseUrl() + endpoint;
            HttpPost post = new HttpPost(url);
            String jsonPayload = objectMapper.writeValueAsString(payload);
            log.info("发送请求到 {}, payload: {}", url, jsonPayload);
            
            post.setEntity(new StringEntity(jsonPayload, ContentType.APPLICATION_JSON));

            return client.execute(post, response -> {
                int statusCode = response.getCode();
                String result = new String(response.getEntity().getContent().readAllBytes());
                log.info("收到响应 [{}]: {}", statusCode, result);
                
                if (statusCode != 200) {
                    log.error("Ollama API返回错误状态码: {}", statusCode);
                    throw new RuntimeException("Ollama API返回错误状态码: " + statusCode);
                }

                try {
                    // 使用TypeReference来正确处理JSON响应
                    Map<String, Object> responseMap = objectMapper.readValue(result, 
                        new com.fasterxml.jackson.core.type.TypeReference<Map<String, Object>>() {});
                    
                    if (responseMap == null) {
                        throw new RuntimeException("Ollama返回空响应");
                    }
                    
                    Object responseObj = responseMap.get("response");
                    if (responseObj == null) {
                        // 检查是否存在错误信息
                        Object error = responseMap.get("error");
                        String errorMsg = error != null ? error.toString() : "未知错误";
                        log.error("Ollama响应中没有response字段: {}", errorMsg);
                        throw new RuntimeException("Ollama响应错误: " + errorMsg);
                    }
                    
                    String generatedText = responseObj.toString();
                    // 如果响应中包含代码块，提取代码部分
                    if (generatedText.contains("```")) {
                        generatedText = extractCodeBlock(generatedText);
                    }
                    
                    return generatedText.trim();
                } catch (Exception e) {
                    log.error("解析Ollama响应失败: {}", e.getMessage());
                    throw new RuntimeException("解析Ollama响应失败: " + e.getMessage());
                }
            });
        } catch (Exception e) {
            log.error("调用Ollama API失败", e);
            throw new RuntimeException("调用Ollama API失败: " + e.getMessage());
        }
    }

    /**
     * 从响应文本中提取代码块
     */
    private String extractCodeBlock(String text) {
        int start = text.indexOf("```");
        if (start == -1) return text;
        
        // 跳过语言标识符
        start = text.indexOf("\n", start) + 1;
        int end = text.indexOf("```", start);
        
        if (end == -1) return text;
        return text.substring(start, end).trim();
    }

    private Map<String, Object> createPromptPayload(String userInput, String systemPrompt) {
        Map<String, Object> payload = new HashMap<>();
        payload.put("model", aiModelConfig.getOllama().getModelName());
        payload.put("prompt", systemPrompt + userInput);
        payload.put("stream", false);
        return payload;
    }
} 